import datetime
import re

from bluesky.model.resource_m import Resource
from bluesky.util import biz, time_util


def to_dtos(rs):
    if not rs:
        return []
    return list(map(lambda t: to_dto(t), rs))


def to_dto(t):
    if not t:
        return None
    return {
        'id': t.id,
        'name': t.name,
        'parent_id': t.parent_id,
        'type': t.type,
        'ext': t.ext,
        'is_delete': t.is_delete,
        'status': t.status,
        'creator': t.creator,
        'creator_nickname': t.creator_nickname,
        'created_time': time_util.to_time_str(t.created_time),
        'updated_time': time_util.to_time_str(t.updated_time),
        'deleted_time': time_util.to_time_str(t.deleted_time),
    }


def to_page(page):
    if not page:
        return page
    records = page['records']

    return {
        'records': list(map(lambda x: to_dto(x), records)),
        'page_num': page['page_num'],
        'page_size': page['page_size'],
        'total': page['total']
    }


def init_from_dto_create(type, action, param):
    rtype_map = biz.resource_type_map
    rt = rtype_map.get(type)
    rt_ext = rt.ext

    table = biz.rtype_table_map.get(type)
    Cls = biz.table_rs_cls_map.get(table)
    rs = Cls()
    rs.name = param.get('name')
    rs.type = type
    rs.ext = param.get('ext')
    rs.status = param.get('status')
    rs.creator = param.get('creator')
    rs.creator_nickname = param.get('creator_nickname')

    # 保留可修改参数
    config = biz.get_resource_type_config(type, action)
    if config and config.get('update_fields'):
        remove_rs_fields(rs, config.get('update_fields'))

    # 参数检测
    check_param(rs, config)

    rid = biz.random_id()
    id_prefix = rt_ext.get('id_prefix')
    if id_prefix:
        rid = id_prefix + rid
    rs.id = rid
    rs.name = rs.name or ''
    rs.parent_id = ''
    rs.ext = rs.ext or '{}'
    rs.is_delete = 0
    rs.status = rs.status or 0
    rs.creator = rs.creator or ''
    rs.creator_nickname = rs.creator_nickname or ''
    rs.created_time = datetime.datetime.now()
    rs.updated_time = datetime.datetime.now()
    rs.deleted_time = None

    return rs


def check_param(rs: Resource, config: dict):
    if not config:
        return
    param_check = config.get('param_check')
    if not param_check:
        return
    for check in param_check:
        field = check.get('field')
        if not field or field == '':
            continue
        msg = check.get('message')
        err = False
        value = biz.get_rs_value(rs, field)

        if check.get('not_null') and value is None:
            if msg is None: msg = f"{field}不能弄为空"
            err = True

        if check.get('is_null') and value is not None:
            if msg is None: msg = f"{field}不能设值"
            err = True

        if not err and check.get('max') is not None and value is not None and float(value) > check.get('max'):
            if msg is None: msg = f"{field}不能超过{check.get('max')}"
            err = True

        if not err and check.get('min') is not None and value is not None and float(value) < check.get('min'):
            if msg is None: msg = f"{field}不能小于${min}"
            err = True

        if not err and check.get('max_length') is not None and value is not None and len(value) > check.get(
                'max_length'):
            if msg is None: msg = f"{field}长度不能超过{check.get('max_length')}个"
            err = True

        if not err and check.get('min_length') is not None and value is not None and len(value) < check.get(
                'min_length'):
            if msg is None: msg = f"{field}长度不能少于{check.get('min_length')}个"
            err = True

        if not err and check.get('regex') is not None and not re.match(check.get('regex'), value):
            if msg is not None: msg = f"${field}值不符合规则：{check.get('regex')}"
            err = True

        if err:
            if not msg:
                msg = '参数错误'
            raise Exception(msg)

        # 强制设置值
        if check.get('value') is not None:
            value = check.get('value')
            biz.set_rs_value(rs, field, value)
        # 设置默认值
        if check.get('default_value') is not None and value is None:
            biz.set_rs_value(rs, field, check.get('default_value'))


def remove_rs_fields(rs: Resource, permit_keys: [str]):
    if not rs or not permit_keys:
        return
    if 'id' not in permit_keys: rs.id = None
    if 'name' not in permit_keys: rs.name = None
    if 'parent_id' not in permit_keys: rs.parent_id = None
    if 'type' not in permit_keys: rs.type = None
    if 'is_delete' not in permit_keys: rs.is_delete = None
    if 'status' not in permit_keys: rs.status = None
    if 'creator' not in permit_keys: rs.creator = None
    if 'creator_nickname' not in permit_keys: rs.creator_nickname = None
    if 'created_time' not in permit_keys: rs.created_time = None
    if 'updated_time' not in permit_keys: rs.updated_time = None
    if 'deleted_time' not in permit_keys: rs.deleted_time = None

    ext_permit_keys = list(filter(lambda x: x.startswith('ext.'), permit_keys))
    ext_substr_permit_keys = list(map(lambda x: x[4:], ext_permit_keys))
    ext = rs.ext
    if ext and ext_substr_permit_keys:
        exist_keys = ext.keys()
        delete_keys = list(filter(lambda x: x not in ext_substr_permit_keys, exist_keys))
        for key in delete_keys:
            del ext[key]
